package example.demo.nospring.plugins;


import example.demo.route.aop.RouteContext;
import example.demo.route.handler.SqlHandlerInterface;
import org.apache.ibatis.executor.statement.PreparedStatementHandler;
import org.apache.ibatis.executor.statement.RoutingStatementHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.jdbc.ConnectionLogger;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.util.ReflectionUtils;

import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Properties;

/**
 * 这个自动就会加入到mybatis里面去，无需配置
 * <p>
 * 第一阶段【会场创建jdbc的statement对象】 第一阶段无需改动sql
 * mybatis的statement先是prepare
 * 第二阶段【执行sql语句】                第二阶段就需要改动sql了
 * 之后要么是query【select】或者是【update，insert，delete】
 */
@Intercepts({
        //Statement prepare(Connection connection, Integer transactionTimeout)  再创建Statement之前做。原生jdbc的

        @Signature(type = StatementHandler.class, method = "prepare",
                args = {Connection.class, Integer.class}),
        //<E> List<E> query(Statement statement, ResultHandler resultHandler)   
        @Signature(type = StatementHandler.class, method = "query",
                args = {Statement.class, ResultHandler.class}),
        @Signature(type = StatementHandler.class, method = "update",
                args = {Statement.class})})
public class RoutePlugin implements Interceptor {


    /**
     * 装饰器模式
     * RoutingStatementHandler会持有【PreparedStatementHandler，CallableStatementHandler，SimpleStatementHandler】
     * RoutingStatementHandler的 delegate 就是上面的其中三个其中的一个
     * 也就是RoutingStatementHandler委托给delegate去做事情。
     * <p>
     * BaseStatementHandler的三个子类【PreparedStatementHandler，CallableStatementHandler，SimpleStatementHandler】
     * 那三个子类都没有自己的属性，都是继承自BaseStatementHandler的
     */
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object target = invocation.getTarget();
        if (target instanceof RoutingStatementHandler) {
            /*委托者*/
            RoutingStatementHandler routingStatementHandler = (RoutingStatementHandler) target;
            Class<RoutingStatementHandler> routingStatementHandlerClass = RoutingStatementHandler.class;

            /*真正的操作人*/
            Field delegate = routingStatementHandlerClass.getDeclaredField("delegate");
            delegate.setAccessible(true);
            StatementHandler statementHandler = (StatementHandler) delegate.get(routingStatementHandler);

            BoundSql boundSql = statementHandler.getBoundSql();
            /**<? 获取到sql语句*/
            String sql = boundSql.getSql();
            /**<? 拿到sql属性*/
            Field sqlField = BoundSql.class.getDeclaredField("sql");
            sqlField.setAccessible(true);
            //修改sql
        }
        /*如果是prepare，则内部是是创建statement对象，update，query的话则内部是执行sql语句*/
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
